package com.tarena.lbs.content.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tarena.lbs.base.protocol.pager.PageResult;
import com.tarena.lbs.business.api.BusinessApi;
import com.tarena.lbs.business.api.pojo.StoreDTO;
import com.tarena.lbs.common.principle.UserPrinciple;
import com.tarena.lbs.common.utils.AuthenticationContextUtils;
import com.tarena.lbs.content.dao.repository.ArticleRepository;
import com.tarena.lbs.content.dao.repository.CategoryRepository;
import com.tarena.lbs.content.pojo.param.ArticleActionParam;
import com.tarena.lbs.content.pojo.param.ArticleContentParam;
import com.tarena.lbs.content.pojo.po.ArticlePO;
import com.tarena.lbs.content.pojo.query.ArticleQuery;
import com.tarena.lbs.content.pojo.vo.ArticleVO;
import com.tarena.lbs.content.service.ArticleService;
import com.tarena.lbs.user.api.UserApi;
import com.tarena.lbs.user.api.pojo.dto.AdminDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class ArticleServiceImpl implements ArticleService {

    @Autowired
    private ArticleRepository articleRepository;

    @DubboReference
    private BusinessApi businessApi;

    @DubboReference
    private UserApi userApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String USER_LOCATION_KEY = "user:location:";
    private static final double SEARCH_RADIUS_KM = 10.0; // 搜索半径10公里


    @Override
    public PageResult<ArticleVO> articleList(ArticleQuery articleQuery) {
        // 如果传入了经纬度，使用Redis GEO查询附近文章
        if (StringUtils.isNotBlank(articleQuery.getLatitude()) &&
                StringUtils.isNotBlank(articleQuery.getLongitude())) {
            return getArticlesByGeoLocation(articleQuery);
        } else {
            // 如果没有经纬度，执行原来的查询逻辑
            return getArticlesWithoutLocation(articleQuery);
        }
    }

    /**
     * 根据地理位置查询附近文章
     */
    private PageResult<ArticleVO> getArticlesByGeoLocation(ArticleQuery articleQuery) {
        try {
            // 1. 使用Redis GEO查询附近10公里内的文章ID
            String geoKey = "article:geo";
            GeoResults<RedisGeoCommands.GeoLocation<String>> geoResults = redisTemplate.opsForGeo()
                    .radius(geoKey,
                            new Circle(new Point(
                                    Double.parseDouble(articleQuery.getLongitude()),
                                    Double.parseDouble(articleQuery.getLatitude())
                            ), new Distance(SEARCH_RADIUS_KM, Metrics.KILOMETERS)),
                            RedisGeoCommands.GeoRadiusCommandArgs.newGeoRadiusArgs()
                                    .includeDistance()
                                    .sortAscending()
                                    .limit(1000L) // 限制返回数量，避免性能问题
                    );

            if (geoResults == null || geoResults.getContent().isEmpty()) {
                return new PageResult<>();
            }

            // 2. 提取文章ID
            List<Integer> nearbyArticleIds = geoResults.getContent().stream()
                    .map(geoLocation -> {
                        try {
                            return Integer.parseInt(geoLocation.getContent().getName());
                        } catch (NumberFormatException e) {
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

            if (nearbyArticleIds.isEmpty()) {
                return new PageResult<>();
            }

            // 3. 根据文章ID查询详细信息
            PageHelper.startPage(articleQuery.getPageNo(), articleQuery.getPageSize());
            List<ArticleVO> articleVOS = articleRepository.articleListByGeo(
                    articleQuery, nearbyArticleIds);

            // 设置分类信息

            PageInfo<ArticleVO> pageInfo = new PageInfo<>(articleVOS);
            PageResult<ArticleVO> pageResult = new PageResult<>();
            pageResult.setPageNo(pageInfo.getPageNum());
            pageResult.setPageSize(pageInfo.getPageSize());
            pageResult.setTotal(pageInfo.getTotal());
            pageResult.setObjects(articleVOS);

            return pageResult;

        } catch (Exception e) {
            // 如果GEO查询失败，降级到普通查询
            log.error("GEO查询失败，降级到普通查询", e);
            return getArticlesWithoutLocation(articleQuery);
        }
    }



    /**
     * 普通查询（无地理位置）
     */
    private PageResult<ArticleVO> getArticlesWithoutLocation(ArticleQuery articleQuery) {
        PageHelper.startPage(articleQuery.getPageNo(), articleQuery.getPageSize());
        List<ArticleVO> articleVOS = articleRepository.articleList(articleQuery);

        PageInfo<ArticleVO> pageInfo = new PageInfo<>(articleVOS);
        PageResult<ArticleVO> pageResult = new PageResult<>();
        pageResult.setPageNo(pageInfo.getPageNum());
        pageResult.setPageSize(pageInfo.getPageSize());
        pageResult.setTotal(pageInfo.getTotal());
        pageResult.setObjects(articleVOS);

        return pageResult;
    }


//    @Override
//    public PageResult<ArticleVO> articleList(ArticleQuery articleQuery) {
//        List<ArticleVO> articleVOS = articleRepository.articleList(articleQuery);
//        PageInfo<ArticleVO> pageInfo = new PageInfo<>(articleVOS);
//        PageResult<ArticleVO> pageResult = new PageResult<>();
//        pageResult.setPageNo(pageInfo.getPageNum());
//        pageResult.setPageSize(pageInfo.getPageSize());
//        pageResult.setTotal(pageInfo.getTotal());
//        pageResult.setObjects(articleVOS);
//        return pageResult;
//    }

    @Override
    public void updateArticle(ArticleContentParam param) {
        ArticlePO articlePO = new ArticlePO();
        BeanUtils.copyProperties(param, articlePO);
        articlePO.setUpdateTime(new Date());
        articleRepository.updateArticle(articlePO);
    }

    @Override
    public void deleteArticle(ArticleContentParam param) {
        ArticlePO articlePO = new ArticlePO();
        articlePO.setId(param.getId());
        articlePO.setStatus(2);
        articleRepository.updateArticle(articlePO);
    }

    @Override
    public ArticleVO articleDetail(String id) {
        ArticleVO articleVO = articleRepository.articleDetail(id);
        return articleVO;
    }

    @Override
    public void insertArticle(ArticleContentParam param) {
        UserPrinciple userPrinciple = AuthenticationContextUtils.get();
        Integer id = userPrinciple.getId();
        AdminDto adminDto=userApi.getAdminById(id);
        ArticlePO articlePO = new ArticlePO();
        BeanUtils.copyProperties(param, articlePO);
        articlePO.setCreateTime(new Date());
        articlePO.setUpdateTime(new Date());
        articlePO.setArticleStatus(0);
        articlePO.setStatus(1);
        articlePO.setUserId(adminDto.getBusinessId());
        articlePO.setUserName(adminDto.getNickname());
        articleRepository.insertArticle(articlePO);
    }

    @Override
    public PageResult<ArticleVO> pageListByAreaId(ArticleQuery query) {
        log.info("根据区域ID查询店铺并查询附近文章: areaId={}", query.getAreaId());
        
        // 1. 根据区域ID查询店铺
        List<StoreDTO> storeDTOS = businessApi.getStoreByAreaId(query.getAreaId());
        if (storeDTOS == null || storeDTOS.isEmpty()) {
            log.info("未找到该区域的店铺");
            // 如果没有找到店铺，返回空结果
            return new PageResult<>();
        }
        
        log.info("找到{}家店铺", storeDTOS.size());

        // 2. 保存原始查询参数，用于分页
        Integer pageNo = query.getPageNo();
        Integer pageSize = query.getPageSize();

        // 3. 先统计总数量，确保分页准确
        int totalCount = 0;
        for (StoreDTO storeDTO : storeDTOS) {
            // 保存当前店铺的经纬度
            String latitude = storeDTO.getStoreLatitude();
            String longitude = storeDTO.getStoreLongitude();

            // 设置当前店铺的经纬度
            query.setLatitude(latitude);
            query.setLongitude(longitude);

            // 查询当前店铺附近的文章
            List<ArticleVO> articles = articleRepository.articleList(query);
            if (articles != null) {
                totalCount += articles.size();
            }
        }

        // 4. 执行实际的分页查询
        List<ArticleVO> allArticles = new ArrayList<>();
        for (StoreDTO storeDTO : storeDTOS) {
            log.debug("查询店铺{}的文章", storeDTO);
            // 重新设置分页参数
            query.setPageNo(pageNo);
            query.setPageSize(pageSize);

            // 设置当前店铺的经纬度
            query.setLatitude(storeDTO.getStoreLatitude());
            query.setLongitude(storeDTO.getStoreLongitude());

            // 查询当前店铺附近的文章
            List<ArticleVO> articles = articleRepository.articleList(query);
            log.debug("店铺的文章数量: {}", articles);
            if (articles != null && !articles.isEmpty()) {
                allArticles.addAll(articles);
            }
        }

        // 5. 构建并返回分页结果
        PageResult<ArticleVO> pageResult = new PageResult<>();
        pageResult.setPageNo(pageNo);
        pageResult.setPageSize(pageSize);
        pageResult.setTotal((long) totalCount);
        pageResult.setObjects(allArticles);

        log.info("查询完成: 共{}篇文章", totalCount);
        return pageResult;
    }

    @Override
    public void articleBehavior(ArticleActionParam param) {
        Integer id = param.getId();
        articleRepository.behavior(id, param.getBehavior());
    }

    /**
     * 更新文章地理位置信息（在文章创建/更新时调用）
     */
    public void updateArticleGeoLocation(Integer articleId, Double longitude, Double latitude) {
        if (articleId == null || longitude == null || latitude == null) {
            return;
        }

        try {
            String geoKey = "article:geo";
            Point point = new Point(longitude, latitude);
            redisTemplate.opsForGeo().add(geoKey, point, articleId.toString());
        } catch (Exception e) {
            log.error("更新文章地理位置失败 articleId: {}", articleId, e);
        }
    }

}
